home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / UTILITIE / CPU_MEMO / 0978.ZIP / FILES3X.ASM < prev    next >
Assembly Source File  |  1987-07-03  |  18KB  |  387 lines

  1. ;****************************************************************************
  2. ; file: files3x.asm    by: Steven M. Gibson, Irvine, CA        created: 06/06/87
  3. ;****************************************************************************
  4. ;
  5. ;          * * * PUBLIC DOMAIN COPYRIGHT RELEASE NOTICE * * *
  6. ;
  7. ; THIS PROGRAM, IN BOTH SOURCE CODE AND OBJECT FORM, HAS BEEN EXPLICITLY
  8. ; PLACED INTO THE PUBLIC DOMAIN BY ITS SOLE AUTHOR AND OWNER, STEVEN GIBSON,
  9. ; OF IRVINE, CA.  IT MAY THEREFORE BE FREELY REPRODUCED, EXCHANGED, UPLOADED
  10. ; AND DOWNLOADED.   HOWEVER THE AUTHOR REQUESTS THAT THIS NOTICE OF RELEASE
  11. ; AND ORIGIN OF AUTHORSHIP BE LEFT INTACT AND THAT THIS PROGRAM OR ITS DIRECT
  12. ; DERRIVATIVES, IF ANY, *NOT* BE SOLD FOR PROFIT.     ALSO, PLEASE KEEP THE
  13. ; ENTIRE SET OF FILES TOGETHER AS ONE PACKAGE.               ----> Thanks
  14. ;
  15. ;****************************************************************************
  16. ;
  17. ;  About The Program: FILES.COM              (source code file: files3x.asm)
  18. ;
  19. ;  "FILES.COM" is a small resident (TSR) program which overcomes a major
  20. ;  glitch in the way IBM has implemented DOS 3.30.  Specifically, it handles
  21. ;  the requirements of explicitly ASKING DOS for additional handles and
  22. ;  keeping a block of RAM available for DOS when this request is made.
  23. ;  Any program can now have up to 256 files open when under 3.0-3.2 (counting
  24. ;  the standard pre-opened default files) if the command "FILES" is issued
  25. ;  first.  This program also has the interesting ability to spontaneously
  26. ;  remove itself ("Un-TSR") from memory after doing its job.
  27. ;
  28. ;  If you wish to suppress the message FILES delivers when it is run, simply
  29. ;  put anything after the command, (like: "files shhh") and it won't say a
  30. ;  word as it goes resident. Otherwise it makes a short (non-commercial)
  31. ;  statement of its intent as it terminates.
  32. ;
  33. ;  NOTE:  This program *ONLY* makes sense when under versions 3.0 thru 3.2
  34. ;         of DOS, and will refuse to run under any earlier DOS versions.
  35. ;      Use the other DOS 3.3 version of FILES.COM  (source: files3x.asm)
  36. ;****************************************************************************
  37. ;
  38. ;             About These SOURCE CODE FILES:
  39. ;
  40. ;  This source code file, and the companion OPENER.ASM source code file, were
  41. ;  written to be instructional, clear, and a bit tutorial in nature. As such
  42. ;  they have been commented more heavily than normal self-communication
  43. ;  would normally dictate.  I hope you will find them interesting, useful,
  44. ;  and not overly verbose.  They are also examples of a general coding style
  45. ;  I've found to endure quite well.  Adopt it if you like it.
  46. ;
  47. ;  NOTE: These files were created using the incredible file editor: BRIEF
  48. ;
  49. ;****************************************************************************
  50. ;
  51. ;    To make a COM file from this ASM source code:
  52. ;
  53. ;    masm files3x, files3x;        <--- assemble the .asm to .obj
  54. ;    link files3x;            <--- link the .obj to .exe
  55. ;    exe2bin files3x files3x.com    <--- convert .exe to .com
  56. ;    del files3x.obj            <--- delete the intermediate debris
  57. ;    del files3x.exe
  58. ;
  59. ;****************************************************************************
  60.  
  61. ;----------------------------------------------------------------------------
  62. ;                 E Q U A T E S
  63. ;----------------------------------------------------------------------------
  64. CR            equ    0Dh
  65. LF            equ    0Ah
  66. COM_TERMINATE        equ    20h        ; .COM program termination
  67.  
  68. DOS_FUNC        equ    21h        ; Interrupt to call DOS
  69.  DOS_PRINTSTRING    equ    09h        ; Dos Sub-Function Defs
  70.  DOS_SET_VECTOR        equ    25h
  71.  DOS_VERSION_NUMBER    equ    30h        ;    "    "
  72.  DOS_STAY_RESIDENT    equ    31h
  73.  DOS_GET_VECTOR        equ    35h
  74.  DOS_CREATE        equ    3Ch        ;    "    "
  75.  DOS_OPEN        equ    3DH
  76.  DOS_ALLOC        equ    48H
  77.  DOS_DEALLOC        equ    49H
  78.  DOS_SETBLOCK        equ    4AH
  79.  DOS_GET_PSP        equ    62h
  80.  SET_HANDLE_COUNT    equ    67h
  81.  
  82. NEW_MAX_HANDLES        equ    256        ; assuming 256 handle params
  83. MINIMUM_VERSION        equ    3 * 256 + 00    ; later than ver: "3"."00"
  84. MAXIMUM_VERSION        equ    3 * 256 + 30    ; earlier than ver: "3"."30"
  85. HANDLE_CLOSED_FLAG    equ    0FFh
  86.  
  87. ;----------------------------------------------------------------------------
  88. ;                  M A C R O S
  89. ;----------------------------------------------------------------------------
  90. zero    MACRO p1            ; this little macro is just too
  91.         xor    p1,p1        ; handy to be without.  Since it
  92.     ENDM                ; "cleanly" zeros any register.
  93.  
  94. ;----------------------------------------------------------------------------
  95. ;               C O D E    S E G M E N T
  96. ;----------------------------------------------------------------------------
  97. CODESEG    SEGMENT BYTE PUBLIC
  98.     ASSUME    CS:CODESEG, DS:CODESEG
  99.     ORG    02Ch            ; pointer to this program's environ
  100. Environment    LABEL WORD
  101.  
  102.     ORG    032h            ; maximum process file handles
  103. MaxHandleCount    LABEL WORD
  104.  
  105.     ORG    034h            ; offset of the handle pointer table
  106. HandleTableOff    LABEL WORD
  107.  
  108.     ORG    036h            ; maximum process file handles
  109. HandleTableSeg    LABEL WORD    
  110.  
  111.     ORG    080h
  112. ParameterCount    LABEL BYTE        ; count of the command-line params
  113.  
  114.     ORG    100h            ; .com programs execute from 0100h
  115. ComStart:    jmp    TransientCode    ; jump past the resident portion
  116.  
  117. ;****************************************************************************
  118. ;               RESIDENT CODE PORTION BEGINS HERE
  119. ;****************************************************************************
  120.  
  121.  
  122. OldDosInt    dd    ?        ; original int 21 vector pointer
  123. HoleSegment    dw    ?        ; segment location of the "hole"
  124.  
  125. ;----------------------------------------------------------------------------
  126. ; NOTE TO THE READER:  The following "resident portion" of the TSR will make
  127. ; *MUCH* more sense if you have FIRST read the "transient portion" below. I
  128. ; suggest that you jump ahead and read that first, then come back to here....
  129. ;----------------------------------------------------------------------------
  130.  
  131. Int21Intercept:
  132. ;----------------------------------------------------------------------------
  133. ;   The transient portion of this program pointed DOS' calling Interrupt 21
  134. ;   here before terminating itself.  Therefore we receive control every time
  135. ;   anyone does an Int21h call to DOS.  (Until we've fulfilled our mission)
  136. ;----------------------------------------------------------------------------
  137.         cmp    ah, DOS_OPEN        ; was the call an open handle?
  138.         je    MakeRoom        ; yep, see if we're alive
  139.         cmp    ah, DOS_CREATE        ; was it a create handle?
  140.         je    MakeRoom        ; yep ....
  141. AbortIntercept:    jmp    Int21Continue        ; (too far for a cond. jmp)
  142.  
  143. MakeRoom:    cmp    cs:HoleSegment, 0    ; did we already do our thing?
  144.         je    AbortIntercept        ; yep, so don't do it again!
  145.  
  146.         push    ax            ; save the caller's calling
  147.         push    bx            ; parameters on his own stack
  148.         push    cx
  149.         push    si
  150.         push    di
  151.         push    ds
  152.         push    es
  153.  
  154. ;----------------------------------------------------------------------------
  155. ;  Free up the memory block, located at "HoleSegment", which was previously
  156. ;  allocated by (and therefore owned by) our transient portion 
  157. ;----------------------------------------------------------------------------
  158.         mov    es, cs:HoleSegment    ; get the segment number
  159.         mov    cs:HoleSegment, 0    ; zero it so we don't again
  160.         mov    ah, DOS_DEALLOC
  161.         int    DOS_FUNC        ; and release that ram block 
  162.  
  163. ;----------------------------------------------------------------------------
  164. ;  And now we reallocate it (or maybe some other free chunk lying around)
  165. ;  to the CURRENTLY running process's identity.  This way the current
  166. ;  process "owns" the block so it too will be released when he terminates.
  167. ;----------------------------------------------------------------------------
  168.         mov    bx, (NEW_MAX_HANDLES+15)/16    ; use paragraphs
  169.         mov    ah, DOS_ALLOC
  170.         int    DOS_FUNC
  171.         mov    es, ax        ; and hold onto the block's segment
  172.  
  173.  
  174. ;----------------------------------------------------------------------------
  175. ;  Now we copy the process's existing handle table into our new table
  176. ;----------------------------------------------------------------------------
  177.         mov    ah, DOS_GET_PSP        ; so get his PSP segment
  178.         int    DOS_FUNC
  179.         mov    ds, bx
  180.         push    ds            ; keep it safe for later
  181.         mov    cx, MaxHandleCount    ; get the number of handles
  182.         mov    bx, cx            ; and keep it for a minute
  183.         mov    si, HandleTableOff    ; get the offset
  184.         mov    ds, HandleTableSeg    ; and segment of the table
  185.         zero    di
  186.         rep movsb            ; and copy the table
  187.  
  188. ;----------------------------------------------------------------------------
  189. ;  Now we must flag the remaining handles as being still closed
  190. ;----------------------------------------------------------------------------
  191.         mov    cx, NEW_MAX_HANDLES
  192.         sub    cx, bx            ; subtract those already done
  193.         jz    SetupTable        ; nothing left to do
  194.  
  195.         mov    al, HANDLE_CLOSED_FLAG
  196.         rep stosb
  197.  
  198. ;----------------------------------------------------------------------------
  199. ;  Now "activate" our new table by pointing his PSP pointers to our table
  200. ;----------------------------------------------------------------------------
  201. SetupTable:    pop    ds            ; recover caller's PSP
  202.         mov    MaxHandleCount, NEW_MAX_HANDLES
  203.         mov    HandleTableOff, 0    ; offset of the new table
  204.         mov    HandleTableSeg, es    ; and the new segment
  205.  
  206. ;----------------------------------------------------------------------------
  207. ;     Now we verify that interrupt 21 is still pointing at us, and if so
  208. ;     we're able to re-point it to where it was originally pointing,
  209. ;     un-vectoring ourselves) then release even ourselves from ram as well!
  210. ;----------------------------------------------------------------------------
  211.         mov    ah, DOS_GET_VECTOR
  212.         mov    al, DOS_FUNC        ; get int 21's address
  213.         int    DOS_FUNC
  214.         cmp    bx, OFFSET Int21Intercept
  215.         jne    RestoreStack        ; it moved, so we must remain
  216.         mov    ax, es            ;
  217.         mov    bx, cs            ; can't compare segment regs,
  218.         cmp    ax, bx            ; <sigh> so we do it this way
  219.         jne    RestoreStack
  220.  
  221.  
  222. ;----------------------------------------------------------------------------
  223. ;  DOS' calling Interrupt 21 is still pointing at us, (as it should always be
  224. ;  unless some later resident program or the currently executing program has
  225. ;  changed it), so we're free to point it back to where it was pointing.
  226. ;----------------------------------------------------------------------------
  227.         push    dx            ; we need dx too, so stack it
  228.         mov    dx, WORD PTR cs:OldDosInt
  229.         mov    ds, WORD PTR cs:OldDosInt+2
  230.         mov    ah, DOS_SET_VECTOR
  231.         mov    al, DOS_FUNC
  232.         int    DOS_FUNC
  233.         pop    dx            ; and restore it
  234.  
  235. ;----------------------------------------------------------------------------
  236. ;  Now, since we're no longer in the Interrupt 21 calling chain, we're free
  237. ;  to leave ram too, so now we can release our own code segment as well!
  238. ;  Since the transient portion already freed our environment allocation, and
  239. ;  we just unhooked ourselves from Int21, this final release of our code seg
  240. ;  will create a contiguous free region underneath the currently running
  241. ;  application program which DOS will collect together and recover as soon
  242. ;  as that programs terminates.  This means that we will have completely
  243. ;  and spontaneously removed ourselves from RAM.
  244. ;----------------------------------------------------------------------------
  245.         mov    ax, cs            ; get our own code segment        
  246.         mov    es, ax
  247.         mov    ah, DOS_DEALLOC
  248.         int    DOS_FUNC        ; and release our ram block 
  249.  
  250. ;----------------------------------------------------------------------------
  251. ;  Now we restore the caller's original parameters (remember, we got control
  252. ;  because he was doing a DOS call himself) and pass control on to DOS so 
  253. ;  that the caller's original job can be performed as if we were never here.
  254. ;----------------------------------------------------------------------------
  255. RestoreStack:    pop    es            ; now restore our working
  256.         pop    ds
  257.         pop    di
  258.         pop    si
  259.         pop    cx
  260.         pop    bx            ; registers
  261.         pop    ax
  262. Int21Continue:    jmp    cs:[OldDosInt]
  263.  
  264. ;****************************************************************************
  265. ;               END OF THE RESIDENT CODE
  266. ;****************************************************************************
  267.  
  268. ;----------------------------------------------------------------------------
  269.  
  270.  
  271. ;****************************************************************************
  272. ;        BEGINNING OF THE TRANSIENT (NON-RESIDENT) CODE
  273. ;****************************************************************************
  274.  
  275. ;----------------------------------------------------------------------------
  276. ;  This program only operates under versions of DOS from 3.0 through 3.2,
  277. ;  so we refuse to operate at all if we're using any other DOS's.
  278. ;----------------------------------------------------------------------------
  279. TransientCode:    mov    ah, DOS_VERSION_NUMBER    ; first we need to make sure
  280.         int    DOS_FUNC        ; this guy has DOS 3.3!
  281.         xchg    ah, al            ; make the number linear
  282.         cmp    ax, MINIMUM_VERSION
  283.         jb    BadDosVersion        ; at least it's not too early
  284.         cmp    ax, MAXIMUM_VERSION
  285.         jb    MakeUsResident        ; and not too late...
  286.  
  287. BadDosVersion:    mov    dx, OFFSET WrongDosMsg    ; nope, he's using a version
  288.         mov    ah, DOS_PRINTSTRING    ; of DOS prior to 3.3
  289.         int    DOS_FUNC
  290.         int    COM_TERMINATE        ; we're not "supposed" to quit
  291.                         ; this way anymore, but it's
  292.                         ; so easy!
  293. MakeUsResident:
  294. ;----------------------------------------------------------------------------
  295. ;  When DOS loads a program it is allocated ALL of the remaining contiguous
  296. ;  memory from its load-point to the end of ram, so we start by modifying
  297. ;  this allocation so that it just encompasses our own program's code...
  298. ;----------------------------------------------------------------------------
  299.         mov    bx, OFFSET EndOfTransient + 15 ; get our ending offset
  300.         mov    cl, 4            ; and compute the number of
  301.         shr    bx, cl            ; segments (the 15 rounds up)
  302.         mov    ah, DOS_SETBLOCK    ; now shrink our memory block
  303.         int    DOS_FUNC
  304.  
  305. ;----------------------------------------------------------------------------
  306. ;  Every program also receives a set of strings in its Environment Block.
  307. ;  Since we don't need this, it's polite to release it too.  (Actually it's
  308. ;  necessary if we, being a TSR, are ever to completely leave RAM.)
  309. ;  (Dos manages memory allocation on a segment-by-segment, paragraph-by-
  310. ;  paragraph basis.  So we always refer to allocated blocks of memory by
  311. ;  referencing that block's segment number.  In the case of our Environment
  312. ;  segment, our own PSP (program segment prefix) has a pointer to its seg.)
  313. ;----------------------------------------------------------------------------
  314.         mov    es, Environment        ; get our environment's seg
  315.         mov    ah, DOS_DEALLOC
  316.         int    DOS_FUNC        ; and release it too!
  317.  
  318. ;----------------------------------------------------------------------------
  319. ;  Now we grab up a block of memory large enough to allow DOS to open 256
  320. ;  files.  
  321. ;----------------------------------------------------------------------------
  322.         mov    bx, (NEW_MAX_HANDLES+15)/16    ; use paragraphs
  323.         mov    ah, DOS_ALLOC
  324.         int    DOS_FUNC
  325.         mov    HoleSegment, ax        ; and save the block's segment
  326.  
  327. ;----------------------------------------------------------------------------
  328. ;  Now, since our whole methodology involves having the resident portion
  329. ;  FREE UP this newly allocated ram block, then ask DOS for a lot of handles
  330. ;  WHEN the next-to-run program asks DOS to open or create a file for it, we
  331. ;  need to intercept all subsequent DOS calls until we're done with our job.
  332. ;  So we re-route Interrupt 21 through our resident half.
  333. ;----------------------------------------------------------------------------
  334.         mov    ah, DOS_GET_VECTOR        ; get the current
  335.         mov    al, DOS_FUNC            ; interrupt 21 value
  336.         int    DOS_FUNC
  337.         mov    WORD PTR OldDosInt  , bx    ; saving it in the
  338.         mov    WORD PTR OldDosInt+2, es    ; resident portion
  339.  
  340.         mov    dx, OFFSET Int21Intercept    ; that done, we set
  341.         mov    ah, DOS_SET_VECTOR        ; int 21 to point
  342.         mov    al, DOS_FUNC            ; to our resident
  343.         int    DOS_FUNC            ; module
  344.  
  345. ;----------------------------------------------------------------------------
  346. ;  Nearly done, and just to be quite clear, we say something appropriate to
  347. ;  our operator before we terminate ... but *ONLY* if he didn't specifically
  348. ;  ask as to remain silent.  The byte at location 80h in our PSP contains
  349. ;  the count of parameters on our invoking command line.  If this is not
  350. ;  zero, we're suppose to suppress all departing exclamation....
  351. ;----------------------------------------------------------------------------
  352.         cmp    ParameterCount, 0        ; is it zero?
  353.         jne    NowWeTSR            ; nope, so be quiet!
  354.  
  355.         mov    dx, OFFSET FilesMessage        ; yep, so we get to
  356.         mov    ah, DOS_PRINTSTRING        ; say goodbye now
  357.         int    DOS_FUNC
  358.  
  359. ;----------------------------------------------------------------------------
  360. ;  Finally we tell DOS that we're all through, asking it nicely to terminate
  361. ;  us but leave the top half of us resident.  That top half will be awakened
  362. ;  every time DOS is called until it's done its job.  "TransientCode" is the
  363. ;  beginning of our second half, and the "+15" does the right thing with
  364. ;  rounding as we convert into our paragraph size.
  365. ;----------------------------------------------------------------------------
  366. NowWeTSR:    mov    ah, DOS_STAY_RESIDENT        ; compute the number
  367.         mov    dx, OFFSET TransientCode + 15    ; of paragraphs to
  368.         mov    cl, 4                ; keep resident
  369.         shr    dx, cl
  370.         int    DOS_FUNC    ; this "call" never returns from DOS
  371.  
  372. ;----------------------------------------------------------------------------
  373. ;              T E X T    M E S S A G E S
  374. ;----------------------------------------------------------------------------
  375. WrongDosMsg    db    CR,LF, "This program only applies to DOS versions "
  376.         db    "3.00 thru 3.20 ... Sorry!",CR,LF,"$"
  377. FilesMessage    db    CR,LF
  378.         db    "The next program to run may open up to "
  379.         db    22h,"FILES=",22h," files."        ; asc(")=22h
  380.         db    CR,LF,"$"
  381. ;----------------------------------------------------------------------------
  382. EndOfTransient    = THIS BYTE        ;  the address of this label is used
  383.                     ;  to compute our load-module size
  384. CODESEG    ENDS
  385.     END    ComStart        ; and that's all there is to it!
  386.  
  387.